//
// Created by jiaxv on 2025/8/11.
//

#include "as_entity.h"
#include "define.h"
#include "interface/ground.h"


static l_err recv_g3_snf_upload(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);
static l_err recv_g3_as_auz_info(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);
static l_err recv_g3_key_trans(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);

size_t g3_format_size = 7;
cn_format_desc_t g3_format_descs[] = {
    {G3_INIT_AS, &g1_g3_init_as_desc, "G1 G3 INIT AS",sizeof(g1_g3_init_as_t), 0, NULL, NULL, default_cn_forward_handler, free_g1_g3_init_as},
    {G3_SNF_UPLOAD, &g1_g3_snf_pkt_desc, "G1 G3 SNF UPLOAD", sizeof(g1_g3_snf_pkt_t), 0, NULL, recv_g3_snf_upload, NULL, free_g1_g3_snf_pkt},
    {G3_SNF_DOWNLOAD, &g1_g3_snf_pkt_desc, "G1 G3 SNF DOWNLOAD", sizeof(g1_g3_snf_pkt_t), 0, NULL, NULL, default_cn_forward_handler, free_g1_g3_snf_pkt},
    {G3_AS_AUZ_INFO, &g3_g5_as_auz_info_desc, "G3 AS AUZ INFO", sizeof(g3_g5_as_auz_info_t), 4, NULL, recv_g3_as_auz_info, NULL, free},
    {G3_KEY_TRANS, &g1_g3_snf_pkt_desc, "G1 G3 KEY TRANS", sizeof(g1_g3_snf_pkt_t), 0, NULL, recv_g3_key_trans, NULL, free_g1_g3_snf_pkt},
    {G3_AS_STATE_CHANGE, &g1_g3_g5_as_st_chg_desc, "G3 G5 STATE CHANGE", sizeof(g1_g3_g5_as_st_chg_t), 5, NULL, NULL, default_cn_forward_handler, free},
    {G3_KEY_UPDATE_REMIND, &g1_g3_key_update_remind_desc, "G1 G3 KEY UPDATE REMIND", sizeof(g1_g3_key_update_remind_t), 7, NULL, NULL, default_cn_forward_handler, free},
};

static l_err recv_g3_snf_upload(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    g1_g3_snf_pkt_t *upload = calloc(1, sizeof(g1_g3_snf_pkt_t));
    // upload->sdu = init_buffer_ptr(in_buf->len - G1_G3_G5_PKT_HEAD_LEN);
    PARSE_DSTR_PKT(in_buf, upload, sdu, g1_g3_snf_pkt_desc, G1_G3_G5_PKT_HEAD_LEN, 0)

    as_entity_t *as = get_as_uenode_by_SAC(net_ele->as_map, upload->AS_SAC);
    if (!as) {
        desc->free_func(upload);
        cn_log_error(net_ele->element_tag, INTERFACE_UNDEFINED, "No such AS, which SAC = %d", upload->AS_SAC);
        return LD_ERR_INTERNAL;
    }

    if (upload->sdu->ptr[0] == 0x42) {
        // 如果是AUC_RESP，才触发AMM的状态切换
        if (change_state(&as->amm_sm, EV_DEFAULT,
                         &(fsm_event_data_t){
                             &amm_fsm_events[AMM_AUTH], NULL})) {
            cn_log_error(net_ele->element_tag, INTERFACE_UNDEFINED, "cant change state correctly");
            desc->free_func(upload);
            return LD_ERR_INVALID;
        }
    }

    cn_format_desc_t *send_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, G1_SNF_UPLOAD);
    if (!send_desc || !send_desc->forward_handler || send_desc->forward_handler(
            net_ele,
            in_buf,
            get_propt(net_ele, INTERFACE_G1, as->current_client_peer_sac),
            INTERFACE_G1
        ) != LD_OK) {
        cn_log_error(net_ele->element_tag, INTERFACE_G1, "Failed to send");
        desc->free_func(upload);
        return LD_ERR_NULL;
    }

    desc->free_func(upload);
    return LD_OK;
}

static l_err recv_g3_as_auz_info(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    g3_g5_as_auz_info_t *auz = NULL;
    if ((auz = parse_sdu(in_buf, desc->f_desc, desc->struct_size)) == NULL) {
        log_error("Parse SDU failed!");
        if (auz)    desc->free_func(auz);
        return LD_ERR_INTERNAL;
    }

    as_entity_t *as = get_as_uenode_by_SAC(net_ele->as_map, auz->AS_SAC);
    if (!as) {
        desc->free_func(auz);
        cn_log_error(net_ele->element_tag, INTERFACE_UNDEFINED, "No such AS, which SAC = %d", auz->AS_SAC);
        return LD_ERR_INTERNAL;
    }

    if (change_state(&as->amm_sm, EV_DEFAULT,
                     &(fsm_event_data_t){
                         &amm_fsm_events[AMM_CONNECTING], NULL})) {
        cn_log_error(net_ele->element_tag, INTERFACE_UNDEFINED, "cant change state correctly");
        desc->free_func(auz);
        return LD_ERR_INVALID;
    }

    // KEY TRANS 报文
    buffer_t *key_trans_buf = init_buffer_unptr();
    CLONE_TO_CHUNK(*key_trans_buf, in_buf->ptr + 4, in_buf->len - 4);

    //从 G3 中找KEY TRANS接收方法
    cn_format_desc_t *key_trans_desc = get_non_sequential_desc(g3_format_size, g3_format_descs, G3_KEY_TRANS);
    if (!key_trans_desc || !key_trans_desc->recv_handler || key_trans_desc->recv_handler(
            net_ele,
            key_trans_desc,
            key_trans_buf,
            NULL
        ) != LD_OK) {
        cn_log_error(net_ele->element_tag, INTERFACE_G3, "Failed to recv key trans");
        free_buffer(key_trans_buf);
        desc->free_func(auz);
        return LD_ERR_NULL;
    }

    // AS AUZ INFO (G5 发送到 DBSM)
    buffer_t *as_auz_info_buf = init_buffer_unptr();
    CLONE_TO_CHUNK(*as_auz_info_buf, in_buf->ptr, 4);
    cn_format_desc_t *as_auz_desc = get_non_sequential_desc(g5_format_size, g5_format_descs, G5_AS_AUZ_INFO);
    if (!as_auz_desc || !as_auz_desc->forward_handler || as_auz_desc->forward_handler(
            net_ele,
            as_auz_info_buf,
            get_propt(net_ele, INTERFACE_G5, 0),
            INTERFACE_G5
        ) != LD_OK) {
        cn_log_error(net_ele->element_tag, INTERFACE_G5, "Failed to recv key trans");
        free_buffer(as_auz_info_buf);
        free_buffer(key_trans_buf);
        desc->free_func(auz);
        return LD_ERR_NULL;
    }
    free_buffer(as_auz_info_buf);
    free_buffer(key_trans_buf);
    desc->free_func(auz);
    return LD_OK;
}

static l_err recv_g3_key_trans(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    g1_g3_snf_pkt_t *key_trans = calloc(1, sizeof(g1_g3_snf_pkt_t));
    // key_trans->sdu = init_buffer_ptr(in_buf->len - G1_G3_G5_PKT_HEAD_LEN);
    PARSE_DSTR_PKT(in_buf, key_trans, sdu, g1_g3_snf_pkt_desc, G1_G3_G5_PKT_HEAD_LEN, 0)

    as_entity_t *as = get_as_uenode_by_SAC(net_ele->as_map, key_trans->AS_SAC);
    if (!as) {
        desc->free_func(key_trans);
        cn_log_error(net_ele->element_tag, INTERFACE_UNDEFINED, "No such AS, which SAC = %d", key_trans->AS_SAC);
        return LD_ERR_INTERNAL;
    }

    element_propt_t *send_propt = NULL;
    if (in_state(&as->amm_sm, "AMM_CONNECTING")) {
        send_propt = get_propt(net_ele, INTERFACE_G1, as->current_client_peer_sac);
    }else if (in_state(&as->amm_sm, "AMM_HO_PREPARE")) {
        send_propt = get_propt(net_ele, INTERFACE_G1, as->next_peer_sac);

        if (change_state(&as->amm_sm, EV_DEFAULT,
                         &(fsm_event_data_t){
                             &amm_fsm_events[AMM_HO_EXECUTE], NULL
                         })) {
            cn_log_error(net_ele->element_tag, INTERFACE_UNDEFINED, "cant change state correctly");
            desc->free_func(key_trans);
            return LD_ERR_INVALID;
        }
    }else {
        cn_log_error(net_ele->element_tag, INTERFACE_G1, "Wrong status");
        return LD_ERR_INVALID;
    }


    cn_format_desc_t *send_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, G1_KEY_TRANS);
    if (!send_desc || !send_desc->forward_handler || send_desc->forward_handler(
            net_ele,
            in_buf,
            send_propt,
            INTERFACE_G1
        ) != LD_OK) {
        cn_log_error(net_ele->element_tag, INTERFACE_G1, "Failed to send");
        desc->free_func(key_trans);
        return LD_ERR_NULL;
    }

    desc->free_func(key_trans);
    return LD_OK;
}
